<script lang="tsx">
import { Component, Vue, Prop } from 'vue-property-decorator'
import { VNodeDirective } from 'vue'

@Component({
  name: 'Carousel',
})
export default class extends Vue {
  render() {
    return (
      <div class='carousel' style={{
        height: this.height > 0 ? this.height + 'px' : '',
      }}>
        <transition-group
          tag='div'
          css={ false }
          onBeforeEnter={ this.beforeEnter }
          onEnter={ this.enter }
          onAfterEnter={ this.afterEnter }
          onBeforeLeave={ this.beforeLeave }
          onLeave={ this.leave }
          onAfterLeave={ this.afterLeave }
        >
          {
            this.$slots.default?.map((slot, index) => (
              <div
                key={ 'carousel-item-' + index }
                {...{ directives: [this.getShowDirectives(index)] }}
              >
                { slot }
              </div>
            ))
          }
        </transition-group>

        <div class='carousel__button left'>
          <button onClick={ this.handleReduce }>
            <i class='iconfont iconleft'></i>
          </button>
        </div>

        <div class='carousel__button right'>
          <button onClick={ this.handleAdd }>
            <i class='iconfont iconright'></i>
          </button>
        </div>
      </div>
    )
  }

  private height = 0

  private length = 0

  mounted() {
    if (this.$slots.default) {
      this.length = this.$slots.default.length
      this.height = this.$slots.default.reduce((prev, item) => {
        const currentHeight = item.componentInstance?.$el.firstElementChild?.clientHeight || 0
        return currentHeight > prev ? currentHeight : prev
      }, 0)
    }
  }

  private current = 0

  /**
   * 移动方向
   * 左：left
   * 右：right
  */
  private direction = 'left'

  @Prop({ type: Number, default: 300 }) duration!: number

  @Prop({ type: String, default: 'linear' }) easing!: string

  handleAdd() {
    this.direction = 'left'
    let _current = this.current + 1
    if (_current > this.length - 1) {
      _current = 0
    }
    this.current = _current
  }

  handleReduce() {
    this.direction = 'right'
    let _current = this.current - 1
    if (_current < 0) {
      _current = this.length - 1
    }
    this.current = _current
  }

  // v-show
  getShowDirectives(index: number): VNodeDirective {
    return { name: 'show', value: index === this.current }
  }

  beforeEnter(el: HTMLElement) {
    this.$anime({
      targets: el,
      translateX: this.direction === 'left' ? '100%' : '-100%',
      duration: 0,
    })
  }

  enter(el: HTMLElement, done: Function) {
    this.$anime({
      targets: el,
      translateX: '0%',
      duration: this.duration,
      easing: this.easing,
    }).finished.then(() => {
      done()
    })
  }

  afterEnter(el: HTMLElement) {
    el.style.transform = ''
  }

  beforeLeave(el: HTMLElement) {
    this.$anime({
      targets: el,
      translateX: '0%',
      duration: 0,
    })
  }

  leave(el: HTMLElement, done: Function) {
    this.$anime({
      targets: el,
      translateX: this.direction === 'left' ? '-100%' : '100%',
      duration: this.duration,
      easing: this.easing,
    }).finished.then(() => {
      done()
    })
  }

  afterLeave(el: HTMLElement) {
    el.style.transform = ''
  }
}

</script>

<style lang="scss" scoped>
  @import url('./assets/icons/iconfont.css');

  $button-size: 30px;
  $button-offset: 10px;

  .carousel {
    width: 100%;
    height: 300px;
    position: relative;
    overflow: hidden;

    .carousel__button {
      position: absolute;
      top: 50%;
      z-index: 9;
      transform: translateY(-50%);
      transition: all 200ms;
      button{
        border: 0;
        background: rgba(0, 0, 0, 0.05);
        border-radius: 50%;
        width: $button-size;
        height: $button-size;
        line-height: $button-size;
        text-align: center;
        cursor: pointer;
        transition: all 200ms;
        i {
          color: rgba(255, 255, 255, 0.8);
        }
        &:hover {
          background: rgba(0, 0, 0, 0.1);
          i {
            color: #FFFFFF;
          }
        }
      }
      &.left {
        left: -$button-size - 10px;
      }
      &.right {
        right: -$button-size - 10px;
      }
    }

    &:hover .carousel__button {
      &.left {
        left: $button-offset;
      }
      &.right {
        right: $button-offset;
      }
    }
  }

  // fade
  .fade-enter, .fade-leave-to {
    opacity: 0;
  }

  .fade-enter-to, .fade-leave {
    opacity: 1;
  }

  .fade-enter-active, .fade-leave-active {
    transition: opacity 500ms;
  }

  // // slider-left
  // .slider-left-enter {
  //   transform: translateX(100%);
  // }

  // .slider-left-enter-to {
  //   transform: translateX(0);
  // }

  // .slider-left-leave {
  //   transform: translateX(0);
  // }

  // .slider-left-leave-to {
  //   transform: translateX(-100%);
  // }

  // .slider-left-enter-active, .slider-left-leave-active {
  //   transition: transform 300ms linear;
  // }

  // // slider-right
  // .slider-right-enter {
  //   transform: translateX(-100%);
  // }

  // .slider-right-enter-to {
  //   transform: translateX(0);
  // }

  // .slider-right-leave {
  //   transform: translateX(0);
  // }

  // .slider-right-leave-to {
  //   transform: translateX(100%);
  // }

  // .slider-right-enter-active, .slider-right-leave-active {
  //   transition: transform 300ms linear;
  // }

</style>
